Phase 9 — Crawl and Index Health, and Enhanced Testing
Markers: ▶ being worked on,
⚑ implemented and waiting to be
reviewed,
✓ done,
✓✗ closed
by deciding not to do it, ? open decision,
unmarked = planned.
- Crawling using synthetic data. A crawl of any size
can be run on one machine without fetching anything from the web. The
pages are made up as the crawl asks for them, so a run repeats exactly
and costs nobody bandwidth.
- ⚑ A synthetic crawl tab is
added to the crawl options. Manage Crawl, then Edit Crawl
Options, gains a tab beside the web crawl one. It keeps the settings that
still mean something for a made-up web and replaces the ones that do not.
- ⚑
The settings about reaching the live web are
dropped.
Repeat type, crawl sleep, robots.txt, restrict sites by url, disallowed
sites and seed sites all describe fetching from real hosts. A made-up web
has no hosts to be polite to and no addresses to restrict.
- ⚑
The shape and size of the made-up web are chosen. A
graph type says how the pages link to one another. A graph size says how
many pages the web holds. A third setting says which pages the crawl
starts from, taking the place of seed sites.
- ⚑
What a page is and what it says are chosen by
chance. One model gives the chance a page is html, pdf or an
image. Another gives the words that appear on it. The same seed gives the
same web every run, so a result can be compared with the one before
it.
- The settings suit both a small check and a large
load. A small web makes it possible to ask whether every page
indexed can be recalled and whether results come back in the order
expected. A large one puts the web server, the queue server and the
fetchers under load worth measuring.
- ⚑
A synthetic crawl makes its own pages rather than fetching
them. Where that tab is the one chosen, the fetcher takes its
pages from a function that generates them in place of
FetchUrl::getPages. Everything after the fetch runs
unchanged, so what is measured is the real crawl. A page is a tuple of
numbers: a grid page steps one along in each component, a tree page
appends each child, a power law page draws its targets by hash. By
domain the tuple is one hyphened label, http://i-j.web/,
so each page is its own company level domain; by path it sits under
http://synth.web/i/j/. The queue server and fetcher see a
plain web crawl; only the fetch call differs. Two rules of Yioop's had
to give: a host with no dot has no company level domain and is dropped,
and five consonants in a row read as spam, so y is now a
vowel there. Run as daemons with errors shown: a grid by path reached 66
pages on one robots.txt, by domain 25 pages on one robots.txt per page,
and a search of the finished index found a made-up word.
- The slowdown over a long crawl is found and
fixed. A synthetic crawl is run long enough for the time per
page to climb. Where it starts climbing says which stage is at fault,
and what that reading names is what gets fixed.
- An index is never left corrupt by a crawl that stops part
way through. Phase 4 added guards that keep a corrupt index
from taking the server down. Those are guards rather than prevention.
This item is the prevention.
- Every point that could leave a half-written entry is
named. The walk covers the partition append, the dictionary
merge and the postings write. What is looked for is a write that a
later read takes as a garbage length or offset.
- A write is either finished or undone, never left part
way. A write goes to a new name and is put in place at the
end, or a small mark says a step was begun. On starting again the mark
says whether to finish the step or drop it.
- The recovery is shown by stopping a crawl on
purpose. A synthetic crawl is driven and the queue server is
stopped at chosen points in the write path. The index is read back
afterward and must come back clean every time.
- Other work, grouped by what it touched. Each is a
deliverable of its own that came up during the arc. They are grouped by
the part of Yioop they concern rather than listed one by one.
- A large download no longer holds the web server or its
memory. One reader pulling a large video stalled every other
request for as long as the download took. A three hundred megabyte video
ended the process outright.
- A large file is drained by the event loop rather than by
the request. A resource request with no byte range is now
deferred, and the whole file case names the file instead of reading it
out. Measured on a two hundred megabyte file: pages answered in twenty
seconds before and under five milliseconds after.
- A request keeps its streaming context while it
waits. The context saying which protocol a reply goes out on
was not saved with the rest of a waiting request. A resumed request
therefore gathered its whole body in memory. It is saved and restored
with the other request state.
- ⚑
A large download over either protocol arrives whole
again. A ten megabyte pdf came back as headers and no body. Three
faults on the deferred file path: a resumed request found no task to hand
its file to, since the task was cleared when the route returned; the
HTTP/1.1 headers were finished from an empty string and said a length of
zero; and a stream whose buffer had drained was closed while its file
still waited. The fiber now sets its own task on entry, the file's size
is passed to the headers, and a stream with a file pending is not
finished. Measured over TLS: both protocols deliver 10,485,755 bytes
identical to the upload; a byte range and a small file still work.
- One block of IP addresses keeps one share of the
link. Files going to the same block divide one turn of the
write loop between them. Several downloads from one place cannot take
several shares. Traffic between Yioop machines keeps a whole turn each.
- A document thumb on a wiki page shows a picture, not a
frame. A resource-thumb mark for a pdf drew an iframe of the
document where no thumbnail was there. The mark is now always a link with
a picture, the thumbnail is made from the document on the first read that
asks for it, and an image thumb draws the thumbnail address rather than
the full picture.
- ⚑
A reader who may not edit, or see a private history or
source, is answered 403. A stranger's arg=edit with a stale
token was quietly downgraded to a page read and served 200; a private
page's source was served at 200 too. The group controller now answers 403
for a writing arg on a request whose token is bad; the wiki component
refuses edit, history and source by the group's Access setting, where only
Read Write Wiki lets a member edit. Walked as a stranger, a member of a
Read group, a member of a Read Write Wiki group, and root.
- ⚑
The server log names the signed in user, marks each reply's
speed, and names a timer that held the loop. Each finished-reply
line carries the username after the address, and its time ends in -slow,
-slower or -slowest by band so one grep finds a band. A timer callback
that runs past a tenth of a second writes a line with its length and the
file and line it was set at, since a request arriving during one waits
the whole of it and two cheap 403s that took 2.6 seconds in the same
second had waited on one such callback.
- ⚑
Every request's completion line in the server log says how
long it took. The line that records a reply's status and size
ran only for an immediate HTTP/1 reply, so no HTTP/2 page and no deferred
request, which is every search, ever logged one. It now runs once on every
reply path, a deferred reply logs after its own environment is applied
with a file reply's true size, a redirect logs as 302, and the line ends
with the milliseconds since the request arrived. Measured here: a search
over h2 22ms, the same page over h1 3ms, a ten megabyte download 2ms to
hand off.
- ⚑
A pdf thumbnail draws a magazine cover as a viewer
does. Two covers came out scrambled or blank. Six faults in the
page reader, each found against a pdftoppm render of the same page.
- A large four ink jpeg keeps its black ink.
Past four million points the picture fell to the drawing library, which
drops the black ink. Such a picture is now read one shade per block, an
eighth the size, in half a second.
- A picture is laid through its soft mask. A
figure paired with a gray mask was laid opaque over the cover. The mask
now sets each point's transparency.
- A composite font is read and its letters reached by
number. Such a font keeps its descriptor on a descendant and
names each letter by a two byte place in the font. The reader follows the
descendant, reads the width table, and walks a run two bytes at a
time.
- A run keeps its zero bytes and its saved
color. Trimming a run cut the zero byte that begins a low
numbered letter, and a color set inside a saved state was read on past
the restore. Only blank space is trimmed, and the color is saved and
restored with the frame.
- Letters are set as far apart as the page
says. The character spacing operator is read and carried on each
run.
- A picture named inside a form the page draws is one
of the page's pictures. A cover that was one photograph inside
one form came out blank. The resources of each form the page draws join
the page's own.